package com.lx.idgenerator.autoconfigure;

import adaper.RedisLeafInfoService;
import com.lx.idgenerator.segement.Segment;
import com.lx.idgenerator.segement.leaf.ILeafInfoService;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.boot.autoconfigure.data.redis.RedisProperties;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.redis.connection.RedisClusterConfiguration;
import org.springframework.data.redis.connection.RedisConnectionFactory;
import org.springframework.data.redis.connection.RedisPassword;
import org.springframework.data.redis.connection.RedisStandaloneConfiguration;
import org.springframework.data.redis.connection.jedis.JedisClientConfiguration;
import org.springframework.data.redis.connection.jedis.JedisConnectionFactory;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.util.StringUtils;
import redis.client.RedisClient;
import redis.client.RedisClientManager;
import redis.client.SegmentRedisClient;
import redis.clients.jedis.JedisPoolConfig;

import java.time.Duration;

/**
 * @author lX
 * @version JDK 8
 * @className RedisConfiguration (此处以class为例)
 * @date 2024/11/10
 * @description TODO
 */

public class RedisConfiguration {



    private com.lx.idgenerator.autoconfigure.RedisProperties masterRedisProperties;
    private com.lx.idgenerator.autoconfigure.RedisProperties backRedisProperties;

    private Long step;






    @Bean
    public RedisClientManager redisClientManager(@Qualifier("masterRedisClient") RedisClient masterRedisClient,@Qualifier("backRedisClient") RedisClient backRedisClient){

        return new RedisClientManager(masterRedisClient,backRedisClient);
    }

    @Bean
    public ILeafInfoService leafInfoService(RedisClientManager redisClientManager){

        return new RedisLeafInfoService(redisClientManager,step);
    }



    private JedisConnectionFactory createMasterRedisConnectionFactory(com.lx.idgenerator.autoconfigure.RedisProperties redisProperties) {
        if("cluster".equals(redisProperties.getMode())){
            return new JedisConnectionFactory(getClusterConfiguration(masterRedisProperties), getJedisClientConfiguration(masterRedisProperties));
        }else {
            return new JedisConnectionFactory(getStandaloneConfig(masterRedisProperties), getJedisClientConfiguration(masterRedisProperties));
        }
    }

    private JedisConnectionFactory createBackRedisConnectionFactory(com.lx.idgenerator.autoconfigure.RedisProperties redisProperties) {
        if("cluster".equals(redisProperties.getMode())){
            return new JedisConnectionFactory(getClusterConfiguration(backRedisProperties), getJedisClientConfiguration(masterRedisProperties));
        }else {
            return new JedisConnectionFactory(getStandaloneConfig(backRedisProperties), getJedisClientConfiguration(masterRedisProperties));
        }
    }

    @Bean("backRedisClient")
    public RedisClient backRedisClient(SegmentRedisProperties segmentRedisProperties){
        backRedisProperties = segmentRedisProperties.getBack();
        step = segmentRedisProperties.getStep();
        RedisTemplate template = new RedisTemplate();
        template.setConnectionFactory(createBackRedisConnectionFactory(backRedisProperties));
        template.afterPropertiesSet();
        SegmentRedisClient redisClient = new SegmentRedisClient(template);
        return redisClient;
    }


    @Bean("masterRedisClient")
    public RedisClient masterRedisClient(SegmentRedisProperties segmentRedisProperties){
        masterRedisProperties = segmentRedisProperties.getMaster();
        step = segmentRedisProperties.getStep();
        RedisTemplate<String, Object> template = new RedisTemplate();
        template.setConnectionFactory(createMasterRedisConnectionFactory(masterRedisProperties));
        template.afterPropertiesSet();
        SegmentRedisClient redisClient = new SegmentRedisClient(template);
        return redisClient;
    }


    private JedisClientConfiguration getJedisClientConfiguration(com.lx.idgenerator.autoconfigure.RedisProperties redisProperties) {
        JedisClientConfiguration.JedisClientConfigurationBuilder builder = applyProperties(redisProperties,JedisClientConfiguration.builder());
        RedisProperties.Pool pool = redisProperties.getJedis().getPool();
        if (pool != null) {
            applyPooling(pool, builder);
        }
        return builder.build();
    }

    private JedisClientConfiguration.JedisClientConfigurationBuilder applyProperties(com.lx.idgenerator.autoconfigure.RedisProperties redisProperties,JedisClientConfiguration.JedisClientConfigurationBuilder builder) {
        if (redisProperties.isSsl()) {
            builder.useSsl();
        }
        if (redisProperties.getTimeout() != null) {
            Duration timeout = redisProperties.getTimeout();
            builder.readTimeout(timeout).connectTimeout(timeout);
        }
        if (StringUtils.hasText(redisProperties.getClientName())){
            builder.clientName(redisProperties.getClientName());
        }
        return builder;
    }

    private void applyPooling(RedisProperties.Pool pool,
                              JedisClientConfiguration.JedisClientConfigurationBuilder builder) {
        builder.usePooling().poolConfig(jedisPoolConfig(pool));
    }

    private JedisPoolConfig jedisPoolConfig(RedisProperties.Pool pool) {
        JedisPoolConfig config = new JedisPoolConfig();
        config.setMaxTotal(pool.getMaxActive());
        config.setMaxIdle(pool.getMaxIdle());
        config.setMinIdle(pool.getMinIdle());
        if (pool.getTimeBetweenEvictionRuns() != null) {
            config.setTimeBetweenEvictionRunsMillis(pool.getTimeBetweenEvictionRuns().toMillis());
        }
        if (pool.getMaxWait() != null) {
            config.setMaxWaitMillis(pool.getMaxWait().toMillis());
        }
        return config;
    }


    private  RedisClusterConfiguration getClusterConfiguration(com.lx.idgenerator.autoconfigure.RedisProperties redisProperties) {


        RedisProperties.Cluster clusterProperties = redisProperties.getCluster();
        RedisClusterConfiguration config = new RedisClusterConfiguration(clusterProperties.getNodes());
        if (clusterProperties.getMaxRedirects() != null) {
            config.setMaxRedirects(clusterProperties.getMaxRedirects());
        }
        if (redisProperties.getPassword() != null) {
            config.setPassword(RedisPassword.of(redisProperties.getPassword()));
        }
        return config;
    }

    protected  RedisStandaloneConfiguration getStandaloneConfig(com.lx.idgenerator.autoconfigure.RedisProperties redisProperties) {
        RedisStandaloneConfiguration config = new RedisStandaloneConfiguration();
        config.setHostName(redisProperties.getHost());
        config.setPort(redisProperties.getPort());
        config.setPassword(RedisPassword.of(redisProperties.getPassword()));
        config.setDatabase(redisProperties.getDatabase());
        return config;
    }



}
